package org.joa.manager.persistence;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;

import org.joa.actor.Actor;
import org.joa.actor.ActorName;

public class FilePersistenceManager implements PersistenceManagerInterface {
    private String basePath;

    public FilePersistenceManager(String basePath) {
        this.basePath = basePath;
    }

    public void storeRevision(Actor actor, long revision) throws IOException {
        File file = getFile(actor.self(), actor.getClass(), revision);
        file.getParentFile().mkdirs();
        byte[] data = serialize(actor);

        OutputStream out = new FileOutputStream(file);
        out.write(data);
        out.close();
    }

    public Actor restoreRevision(ActorName actorName, Class<? extends Actor> actorClass,
        long revision) throws IOException, ClassNotFoundException, IllegalArgumentException,
        IllegalAccessException {
        File file = getFile(actorName, actorClass, revision);

        byte[] data = new byte[(int) file.length()];

        InputStream in = new FileInputStream(file);
        in.read(data);
        in.close();

        return deserialize(data, actorClass);
    }

    public byte[] serialize(Actor actor) throws IOException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(actor);
        out.close();
        return byteOut.toByteArray();
    }

    public Actor deserialize(byte[] data, Class<? extends Actor> actorClass) throws IOException,
        ClassNotFoundException, IllegalArgumentException, IllegalAccessException {
        ByteArrayInputStream byteIn = new ByteArrayInputStream(data);
        ObjectInputStream in = new ObjectInputStream(byteIn);

        try {
            return (Actor) in.readObject();
        } finally {
            in.close();
        }
    }

    protected File getFile(ActorName actorName, Class<? extends Actor> actorClass, long revision) {
        return new File(basePath + File.separator + actorClass.getName() + File.separator +
            actorName + File.separator + "r" + revision);
    }
}
